/**
 * Copyright (c) 2014-2016 www.nryuncang.com. All Rights Reserved.
 */
package com.topisv.tms.service.print.impl;

import static com.google.common.base.Preconditions.checkArgument;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.mapper.JsonMapper;

import com.topisv.tms.entity.EdiOrder;
import com.topisv.tms.entity.ExpressConfigure;
import com.topisv.tms.entity.ExpressStyle;
import com.topisv.tms.entity.WarehouseAddress;
import com.topisv.tms.entity.work.WorkOrder;
import com.topisv.tms.entity.work.WorkTask;
import com.topisv.tms.mybatis.SqlMapDao;
import com.topisv.tms.repository.EdiOrderDao;
import com.topisv.tms.service.ExpressConfigureService;
import com.topisv.tms.service.WarehouseAddressService;
import com.topisv.tms.service.work.WorkOrderService;
import com.topisv.tms.service.work.WorkTaskService;
import com.topisv.tms.utils.ExpressUtil;

/**
 * 中通打印
 *
 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
 * @version 0.0.16
 */
@Component
public class ZTOPrintServiceImpl extends AbstractPrintService {
	
	private static final Logger logger = LoggerFactory.getLogger(ZTOPrintServiceImpl.class);
	
	@Autowired
	private WorkTaskService workTaskService;
	@Autowired
	private ExpressConfigureService expressConfigureService;
	@Autowired
	private WarehouseAddressService warehouseAddressService;
	@Autowired
	private SqlMapDao sqlMapDao;
	@Autowired
	private WorkOrderService workOrderService;
	@Autowired
	private EdiOrderDao ediOrderDao;

	// 中通常量
	private static final String ZTO_ORDER_BATCH_SUBMIT = "order.batch_submit";
	@SuppressWarnings("unused") private static final String ZTO_ORDER_SUBMIT = "order.submit";
	@SuppressWarnings("unused") private static final String ZTO_ORDER_CANCEL = "order.cancel";
	@SuppressWarnings("unused") private static final String ZTO_ORDER_MARKE = "order.marke";
	@SuppressWarnings("unused") private static final String ZTO_MAIL_TRACE = "mail.trace"; // 签收图片接口
	@SuppressWarnings("unused") private static final String ZTO_MAIL_BILLIMG = "mail.billimg"; // 快件追踪接口
	@SuppressWarnings("unused") private static final String ZTO_MAIL_STATUS = "mail.status";
	@SuppressWarnings("unused") private static final String ZTO_MAIL_COUNTER = "mail.counter";

	@SuppressWarnings("unchecked")
    @Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public List<EdiOrder> doGetExpressNo(List<String> orderNoList, ExpressStyle template, String taskCode) throws Exception {

		// 第一步:得到基础信息如作业任务，订单列表、仓库信息、配置信息
		WorkTask workTask = workTaskService.loadTaskByCode(taskCode);
		ExpressConfigure expressConfigure = expressConfigureService.findByWarehouseAndCompany(workTask.getWarehouseCode(), 
				template.getLogisticsCompany().getCompanyCode());
		
		WarehouseAddress warehouseAddress = warehouseAddressService.findByWarehouseCode(workTask.getWarehouseCode());
		List<EdiOrder> ediOrderList = sqlMapDao.selectList("ediOrderMapper.getEdiOrderListByOrdeno", orderNoList);

		// 第二步:拼装报文
		List<Map<String, Object>> ztoXmlList = new ArrayList<>();
		for (EdiOrder ediOrder : ediOrderList) {
			
			WorkOrder workOrder = workOrderService.loadOrder(ediOrder.getBatchTaskCode(), ediOrder.getOrdeno());
			if (workOrder.getEbillNo() == null || "cbill".equals(workOrder.getBillType()) 
					|| !template.getLogisticsCompany().getCompanyCode().equals(workOrder.getExpressCompany())) {
				
				ztoXmlList.add(getZTOXmlMap(ediOrder, warehouseAddress));
			
			}
		}
		
		//ztoXmlList表示不用重新再用接口取单号
		if (ztoXmlList != null && !ztoXmlList.isEmpty()){
		
			//报文
			String content = JsonMapper.nonDefaultMapper().toJson(ztoXmlList);
			logger.info("ZTO取单号的报文={}",  content);
			
			// 第三步:调用接口，并接收返回值，对返回值进行解析赋值
			String returnData = returnZTOResult(expressConfigure, content, ZTO_ORDER_BATCH_SUBMIT);
			logger.info("ZTO取单号返回的报文={}",  returnData);
			
			Map<String, Object> mapJson =  JsonMapper.nonDefaultMapper().fromJson(returnData, Map.class);
			if (Boolean.valueOf(String.valueOf(mapJson.get("result")))) {
				List<Map<String, Object>> resultList = (List<Map<String, Object>>) mapJson.get("keys");
				for (Map<String, Object> m : resultList) {
					String result = String.valueOf(m.get("result"));
					if (!"true".equals(result)) {
						logger.error("ZTO 返回失败:{}",m);
						throw new RuntimeException(String.format("ZTO result false %s", m));
					}
					
					String orderId = (String) m.get("orderid");//订单号
					String mailno = (String) m.get("mailno");// 运单号
					String mark = (String) m.get("mark");	// 大头笔
					String sitename = (String) m.get("sitename");// 站点名称
					
					for (EdiOrder ediOrder : ediOrderList) {
						if (ediOrder.getOrdeno().equals(orderId)) {
							ediOrder.setMailNo(mailno);
							ediOrder.setToShortAddress(mark);
							ediOrder.setMessage(StringUtils.isEmpty(sitename) ? "广州市场部" : sitename);
							ediOrder.setCacode(template.getLogisticsCompany().getCompanyCode());//快递公司代码
							ediOrder.setCaname(template.getLogisticsCompany().getCompanyName());//快递公司名称
						}
					}
				}
			} else {
				logger.error("ZTO 获取单号失败:{}",mapJson);
				throw new RuntimeException("ZTO 获取单号失败!");
			}
		}
		ediOrderDao.save(ediOrderList);
		return ediOrderList;
	}

	/**
	 * 中通取运单号请求报文
	 * 
	 * @param orderMap
	 *            订单信息
	 * @param warehouseAddressMap
	 *            寄件地址信息
	 * @return xml报文
	 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
	 * @version 0.0.16
	 */
	private Map<String, Object> getZTOXmlMap(EdiOrder order, WarehouseAddress warehouseAddress) {

		//寄件人信息
		Map<String, Object> senderMap = new HashMap<String, Object>();
		senderMap.put("name", warehouseAddress.getContact());// 寄件人名称
		senderMap.put("mobile", warehouseAddress.getMobile());//寄件人电话
		senderMap.put("phone", "");
		//寄件人城市(省+市+区)
		senderMap.put("city", new StringBuilder().append(warehouseAddress.getProvName() + ",")
				.append(warehouseAddress.getCityName() + ",").append(warehouseAddress.getDistName()).toString());
		senderMap.put("address", warehouseAddress.getAddress());//寄件人地址

		//收件人信息
		Map<String, Object> receiverMap = new HashMap<String, Object>();
		receiverMap.put("name", order.getRecena());//姓名
		receiverMap.put("mobile", order.getMobile());//手机号
		receiverMap.put("phone", order.getTeleph());//电话
		//城市(省+市+区)
		receiverMap.put("city", new StringBuilder().append(order.getProvna() + ",").append(order.getCityna() + ",")
				.append(order.getDistna()).toString());
		receiverMap.put("address", order.getAddres());//地址

		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("id", order.getOrdeno());
		contentMap.put("mailno", "");
		contentMap.put("sender", senderMap);
		contentMap.put("receiver", receiverMap);
		return contentMap;
	}

	/**
	 * 
	 * 发送ZTO接口 post，返回请求结果
	 *
	 * @param expressConfigure
	 *            zto配置信息(url,用户名、密码)
	 * @param content
	 *            报文
	 * @param func
	 *            要调用的方法
	 * @return
	 * @throws IOException
	 *             [参数说明]
	 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
	 * @version 0.0.16
	 */
	private String returnZTOResult(ExpressConfigure expressConfigure, String content, String func)
			throws Exception {
		//获取账号、密码、url
		String partner = expressConfigure.getAccount();
		String pwd = expressConfigure.getPassword();
		String url =  expressConfigure.getUrl();

		// 校验账号、密码、地址
		checkArgument(StringUtils.isNotEmpty(partner), String.format("账号partner is empty"));
		checkArgument(StringUtils.isNotEmpty(pwd), String.format("密码pwd is empty"));
		checkArgument(StringUtils.isNotEmpty(url), String.format("请求地址url is empty"));
		
		//参数
		String datetime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		parameters.add(new BasicNameValuePair("content", ExpressUtil.encryptBASE64(content)));
		parameters.add(new BasicNameValuePair("style", "json"));
		parameters.add(new BasicNameValuePair("func", func));
		parameters.add(new BasicNameValuePair("partner", partner));
		parameters.add(new BasicNameValuePair("datetime", datetime));
		parameters.add(new BasicNameValuePair("verify", ExpressUtil.digestMD5ZTO(partner + datetime + ExpressUtil.encryptBASE64(content) + pwd)));
		
		return super.requestExpressNo(url, parameters);
	}

}
